# -*- coding: utf-8 -*-
from flask import Blueprint, g
from sqlalchemy import case, func, literal
from sqlalchemy.orm import aliased
from common.response import success, error
from common.error_code import ErrorCode
from dao.class_dao import ClassSubjectTeacher
from filter.auth import auth_required
from filter.decorators import validate_request, require_role
from model.request import AddStudentsToGroupRequest, CreateStudyGroupRequest, ListGroupMembersRequest, ListStudyGroupsRequest, RemoveStudentFromGroupRequest, SetGroupLeaderRequest, UpdateStudyGroupRequest
from dao.db import db
from dao.user_dao import Class, Student, Teacher, User
from dao.group_dao import StudyGroup

# 创建学习小组蓝图
group_bp = Blueprint('group', __name__, url_prefix='/api/group')

@group_bp.route('/create', methods=['POST'])
@auth_required
@require_role(['admin', 'teacher'])
@validate_request(CreateStudyGroupRequest)
def create_study_group():
    """创建学习小组接口"""
    data = g.request_data

    # 1. 检查班级是否存在
    cls = Class.query.get(data.class_id)
    if not cls:
        return error(ErrorCode.NOT_FOUND, "班级不存在")

    # 2. 检查班级是否已毕业
    if cls.grade >= 10:
        return error(ErrorCode.FORBIDDEN, "该班级已毕业，不能创建学习小组")

    # 3. 权限检查（teacher必须是班主任）
    if g.role == 'teacher':
        teacher = Teacher.query.filter_by(user_id=g.user_id).first()
        if not teacher or teacher.id != cls.head_teacher_id:
            return error(ErrorCode.FORBIDDEN, "你不是该班级的班主任，无权创建学习小组")

    # 4. 检查同班级内小组名称是否重复
    if StudyGroup.query.filter_by(class_id=data.class_id, name=data.name).first():
        return error(ErrorCode.INVALID_PARAM, "该班级已存在同名学习小组")

    # 5. 创建学习小组（组长初始为空）
    new_group = StudyGroup(
        name=data.name,
        class_id=data.class_id,
        leader_id=None
    )
    db.session.add(new_group)
    db.session.commit()

    return success({
        "group_id": new_group.id,
        "name": new_group.name,
        "class_id": new_group.class_id,
        "leader_id": new_group.leader_id
    })

@group_bp.route('/update', methods=['POST'])
@auth_required
@require_role(['admin', 'teacher'])
@validate_request(UpdateStudyGroupRequest)
def update_study_group():
    """编辑学习小组信息接口"""
    data = g.request_data

    # 1. 检查小组是否存在
    group = StudyGroup.query.get(data.group_id)
    if not group:
        return error(ErrorCode.NOT_FOUND, "学习小组不存在")

    # 2. 权限检查（teacher必须是当前班级的班主任）
    if g.role == 'teacher':
        teacher = Teacher.query.filter_by(user_id=g.user_id).first()
        if not teacher or teacher.id != group.class_info.head_teacher_id:
            return error(ErrorCode.FORBIDDEN, "你不是该小组所在班级的班主任，无权编辑")

    # 3. 如果修改班级
    if data.class_id is not None and data.class_id != group.class_id:
        # 3.1 检查新班级是否存在
        new_class = Class.query.get(data.class_id)
        if not new_class:
            return error(ErrorCode.NOT_FOUND, "新班级不存在")

        # 3.2 检查新班级是否已毕业
        if new_class.grade >= 10:
            return error(ErrorCode.FORBIDDEN, "不能将小组移至已毕业班级")

        # 3.3 检查小组中所有学生是否都属于新班级
        students_in_group = Student.query.filter_by(group_id=data.group_id).all()
        for student in students_in_group:
            if student.class_id != data.class_id:
                return error(
                    ErrorCode.INVALID_PARAM,
                    "小组中存在不属于新班级的学生，请先清空小组再更改班级"
                )

        # 3.4 如果通过检查，更新班级ID
        group.class_id = data.class_id

    # 4. 如果修改小组名称
    if data.name is not None and data.name != group.name:
        # 4.1 检查同班级内小组名称是否重复
        if StudyGroup.query.filter_by(class_id=group.class_id, name=data.name).first():
            return error(ErrorCode.INVALID_PARAM, "该班级已存在同名学习小组")
        group.name = data.name

    # 5. 保存更新
    db.session.commit()

    return success({
        "group_id": group.id,
        "name": group.name,
        "class_id": group.class_id,
        "leader_id": group.leader_id
    })

@group_bp.route('/add-students', methods=['POST'])
@auth_required
@require_role(['admin', 'teacher'])
@validate_request(AddStudentsToGroupRequest)
def add_students_to_group():
    """批量将学生加入学习小组"""
    data = g.request_data

    # 1. 检查小组是否存在
    group = StudyGroup.query.get(data.group_id)
    if not group:
        return error(ErrorCode.NOT_FOUND, "学习小组不存在")

    # 2. 权限检查（teacher必须是该小组所属班级的班主任）
    if g.role == 'teacher':
        teacher = Teacher.query.filter_by(user_id=g.user_id).first()
        if not teacher or teacher.id != group.class_info.head_teacher_id:
            return error(ErrorCode.FORBIDDEN, "你不是该小组所在班级的班主任，无权操作")

    # 3. 检查学生列表是否为空
    if not data.student_ids:
        return error(ErrorCode.INVALID_PARAM, "学生ID列表不能为空")

    # 4. 验证每个学生
    group_class_id = group.class_id
    success_count = 0
    failed_students = []
    for student_id in data.student_ids:
        student = Student.query.get(student_id)
        if not student:
            failed_students.append({
                "student_id": student_id,
                "reason": "学生不存在"
            })
            continue

        # 检查学生是否已加入其他小组
        if student.group_id is not None:
            failed_students.append({
                "student_id": student_id,
                "reason": "该学生已加入其他小组"
            })
            continue

        # 检查学生班级是否与小组班级一致
        if student.class_id != group_class_id:
            failed_students.append({
                "student_id": student_id,
                "reason": "学生班级与小组班级不一致"
            })
            continue

        # 通过所有检查，加入小组
        student.group_id = data.group_id
        success_count += 1

    # 5. 保存更改
    db.session.commit()

    # 6. 返回结果
    return success({
        "success_count": success_count,
        "failed_students": failed_students
    })

@group_bp.route('/set-leader', methods=['POST'])
@auth_required
@require_role(['admin', 'teacher'])
@validate_request(SetGroupLeaderRequest)
def set_group_leader():
    """指定小组组长接口"""
    data = g.request_data

    # 1. 检查小组是否存在
    group = StudyGroup.query.get(data.group_id)
    if not group:
        return error(ErrorCode.NOT_FOUND, "学习小组不存在")

    # 2. 权限检查（teacher必须是该小组所属班级的班主任）
    if g.role == 'teacher':
        teacher = Teacher.query.filter_by(user_id=g.user_id).first()
        if not teacher or teacher.id != group.class_info.head_teacher_id:
            return error(ErrorCode.FORBIDDEN, "你不是该小组所在班级的班主任，无权操作")

    # 3. 检查组长是否存在且已加入该小组
    leader_student = Student.query.get(data.leader_id)
    if not leader_student:
        return error(ErrorCode.NOT_FOUND, "组长学生不存在")

    if leader_student.group_id != data.group_id:
        return error(ErrorCode.INVALID_PARAM, "该学生未加入此学习小组，不能设为组长")

    # 4. 更新组长ID
    group.leader_id = data.leader_id
    db.session.commit()

    return success({
        "group_id": group.id,
        "name": group.name,
        "leader_id": group.leader_id,
        "leader_name": leader_student.user.name
    })

@group_bp.route('/remove-student', methods=['POST'])
@auth_required
@require_role(['admin', 'teacher'])
@validate_request(RemoveStudentFromGroupRequest)
def remove_student_from_group():
    """将学生移出小组接口"""
    data = g.request_data

    # 1. 检查小组是否存在
    group = StudyGroup.query.get(data.group_id)
    if not group:
        return error(ErrorCode.NOT_FOUND, "学习小组不存在")

    # 2. 权限检查（teacher必须是该小组所属班级的班主任）
    if g.role == 'teacher':
        teacher = Teacher.query.filter_by(user_id=g.user_id).first()
        if not teacher or teacher.id != group.class_info.head_teacher_id:
            return error(ErrorCode.FORBIDDEN, "你不是该小组所在班级的班主任，无权操作")

    # 3. 检查学生是否存在且是该小组成员
    student = Student.query.get(data.student_id)
    if not student:
        return error(ErrorCode.NOT_FOUND, "学生不存在")

    if student.group_id != data.group_id:
        return error(ErrorCode.INVALID_PARAM, "该学生不是此学习小组的成员")

    # 4. 如果该学生是组长，则移除组长设置
    if group.leader_id == data.student_id:
        group.leader_id = None

    # 5. 将学生移出小组
    student.group_id = None

    # 6. 保存更改
    db.session.commit()

    return success({
        "group_id": group.id,
        "name": group.name,
        "removed_student_id": data.student_id,
        "removed_student_name": student.user.name,
        "new_leader_id": group.leader_id
    })

@group_bp.route('/list', methods=['POST'])
@auth_required
@validate_request(ListStudyGroupsRequest)
def list_study_groups():
    """查看学习小组列表接口"""
    params = g.request_data
    name_keyword = params.name.strip() if params.name else None

    # 1. 根据角色处理 class_id
    if g.role == 'admin':
        # admin 可查所有班级，class_id 可选
        query_class_id = params.class_id
    elif g.role == 'teacher':
        # teacher 必须传 class_id，且必须是班主任或任课老师
        if not params.class_id:
            return error(ErrorCode.INVALID_PARAM, "教师调用时class_id为必选参数")
        
        cls = Class.query.get(params.class_id)
        if not cls:
            return error(ErrorCode.NOT_FOUND, f"班级ID={params.class_id}不存在")
        
        teacher = Teacher.query.filter_by(user_id=g.user_id).first()
        is_head_teacher = (cls.head_teacher_id == teacher.id)
        is_subject_teacher = ClassSubjectTeacher.query.filter_by(
            class_id=params.class_id,
            teacher_id=teacher.id
        ).first()
        
        if not is_head_teacher and not is_subject_teacher:
            return error(ErrorCode.FORBIDDEN, "你不是该班级的班主任或任课老师，无权查询")
        
        query_class_id = params.class_id
    else:  # student
        # student 只能查自己所在班级
        student = Student.query.filter_by(user_id=g.user_id).first()
        if not student:
            return error(ErrorCode.NOT_FOUND, "学生信息不存在")
        
        query_class_id = student.class_id

    # 2. 构建查询
    # 别名：一个表示组长(leader_student)，一个表示成员(member_student)
    LeaderStudent = aliased(Student)
    MemberStudent = aliased(Student)
    base_query = db.session.query(
        StudyGroup,
        Class.name.label('class_name'),
        Class.grade,
        User.id.label('leader_user_id'),
        User.name.label('leader_name'),
        func.count(MemberStudent.id).label('member_count')
    ).join(Class, StudyGroup.class_id == Class.id
    ).outerjoin(LeaderStudent, StudyGroup.leader_id == LeaderStudent.id
    ).outerjoin(User, LeaderStudent.user_id == User.id
    ).outerjoin(MemberStudent, StudyGroup.id == MemberStudent.group_id
    ).group_by(StudyGroup.id, Class.name, Class.grade, User.id, User.name)

    # 3. 应用筛选条件
    if query_class_id:
        base_query = base_query.filter(StudyGroup.class_id == query_class_id)

    if name_keyword:
        base_query = base_query.filter(StudyGroup.name.like(f'%{name_keyword}%'))

    # 4. 执行查询
    groups = base_query.all()

    # 5. 格式化返回
    result = []
    for group, class_name, grade, leader_user_id, leader_name, member_count in groups:
        result.append({
            "group_id": group.id,
            "name": group.name,
            "member_count": member_count,
            "leader_id": group.leader_id,
            "leader_name": leader_name,
            "class_id": group.class_id,
            "class_name": class_name,
            "grade": grade
        })

    return success(result)

@group_bp.route('/members', methods=['POST'])
@auth_required
@validate_request(ListGroupMembersRequest)
def list_group_members():
    """查看小组成员列表接口"""
    params = g.request_data

    # 1. 检查小组是否存在
    group = StudyGroup.query.get(params.group_id)
    if not group:
        return error(ErrorCode.NOT_FOUND, "学习小组不存在")

    # 2. 权限控制
    if g.role == 'teacher':
        # 检查是否是该班级的班主任或任课老师
        cls = Class.query.get(group.class_id)
        teacher = Teacher.query.filter_by(user_id=g.user_id).first()
        is_head_teacher = (cls.head_teacher_id == teacher.id)
        is_subject_teacher = ClassSubjectTeacher.query.filter_by(
            class_id=group.class_id,
            teacher_id=teacher.id
        ).first()
        
        if not is_head_teacher and not is_subject_teacher:
            return error(ErrorCode.FORBIDDEN, "你不是该小组所在班级的班主任或任课老师，无权查询")
    elif g.role == 'student':
        # 检查是否是该小组成员
        student = Student.query.filter_by(user_id=g.user_id).first()
        if not student or student.group_id != params.group_id:
            return error(ErrorCode.FORBIDDEN, "你不是该小组的成员，无权查询")

    # 3. 查询小组成员
    members_query = db.session.query(
        Student.id.label('student_id'),
        User.name.label('student_name'),
        Class.name.label('class_name'),
        Class.grade,
        Student.student_id.label('student_number'),
        case(
            (Student.id == group.leader_id, literal(True)),
            else_=literal(False)
        ).label('is_leader')
    ).join(User, Student.user_id == User.id
    ).join(Class, Student.class_id == Class.id
    ).filter(Student.group_id == params.group_id)

    # 4. 排序：组长在前，其余按学号升序
    members_query = members_query.order_by(
        case(
            (Student.id == group.leader_id, literal(0)),
            else_=literal(1)
        ),
        Student.student_id.asc()
    )

    members = members_query.all()

    # 5. 格式化返回
    result = [
        {
            "student_id": m.student_id,
            "name": m.student_name,
            "class_name": m.class_name,
            "grade": m.grade,
            "student_number": m.student_number,
            "is_leader": m.is_leader
        }
        for m in members
    ]

    return success(result)